﻿using System;
using System.Timers;

using Bootstrap5.Abstractions;

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;

namespace Bootstrap5;

internal class ToastBox:BootstrapChildContentWithChildCascadingComponentBase<ToastBox,ToastContainer>,IDisposable
{
    /// <summary>
    /// Gets or sets the identifier.
    /// </summary>
    /// <value>
    /// The identifier.
    /// </value>
    [Parameter] public Guid Id { get; set; }
    /// <summary>
    /// Gets or sets the setting.
    /// </summary>
    /// <value>
    /// The setting.
    /// </value>
    [Parameter] public ToastOptions Options { get; set; }
    /// <summary>
    /// Gets or sets the timeout.
    /// </summary>
    /// <value>
    /// The timeout.
    /// </value>
    [Parameter] public int? Interval { get; set; }

    /// <summary>
    /// Gets or sets the fade interval.
    /// </summary>
    [Parameter] public int FadeInterval { get; set; }

    private ToastCountdownTimer _countdownTimer;
    private int _progress = 0;

    private Timer _transitionTimer;

    private float _opacity = 0;

    /// <summary>
    /// Method invoked when the component is ready to start, having received its
    /// initial parameters from its parent in the render tree.
    /// </summary>
    protected override void OnInitialized()
    {
        ThrowIfParentNull();

        if (Interval.HasValue)
        {
            _progress =100;

            _countdownTimer = new ToastCountdownTimer(Interval.Value);
            _countdownTimer.OnTick += CalculateProgress;
            _countdownTimer.OnElapsed += () => Close();
            _countdownTimer.Start();
        }
        _transitionTimer = new Timer(FadeInterval);
        _transitionTimer.Start();
        _transitionTimer.Elapsed += async (sender, e) =>
        {
            if (_opacity <= 1)
            {
                _opacity += 0.1f;
                await InvokeAsync(StateHasChanged);
            }
            else
            {
                _transitionTimer.Stop();
            }
        };
    }
    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        _countdownTimer.Dispose();
        _countdownTimer = null;
        _transitionTimer.Dispose();
        _transitionTimer = null;
    }
    /// <summary>
    /// Calculates the progress.
    /// </summary>
    /// <param name="percentComplete">The percent complete.</param>
    private async void CalculateProgress(int percentComplete)
    {
        _progress =  100 - percentComplete;
        await InvokeAsync(StateHasChanged);
    }
    /// <summary>
    /// Closes this toast.
    /// </summary>
    private void Close()
    {
        _transitionTimer?.Dispose();

        _transitionTimer = new Timer(FadeInterval);
        _transitionTimer.Start();
        _transitionTimer.Elapsed += async (sender, e) =>
        {
            if (_opacity >= 0)
            {
                _opacity -= 0.1f;
                await InvokeAsync(StateHasChanged);
            }
            else
            {
                _transitionTimer.Stop();
                Parent.Remove(Id);
            }
        };
    }

	protected override void BuildRenderTree(RenderTreeBuilder builder)
	{
        builder.OpenComponent<Toast>(0);
        builder.AddAttribute(1, nameof(Toast.Closable), Options.Closable);
        if (Options.Title is not null)
        {
            builder.AddAttribute(2, nameof(Toast.HeadContent), (RenderFragment)(header =>
            {
                header.OpenElement(0, "strong");
                header.AddAttribute(1, "me-auto");
                header.AddContent(0, Options.Title);
                header.CloseElement();
            }));
        }
        builder.AddAttribute(3, nameof(Toast.Color), Options.Color);
        builder.AddAttribute(4, "style", $"opacity:{_opacity}");
        builder.AddAttribute(5, nameof(Toast.AdditionalCssClass), "show");
        builder.AddAttribute(10, nameof(Toast.ChildContent), (RenderFragment)(child =>
        {
            child.AddContent(0, Options.Message);
        }));
        builder.CloseComponent();
	}
}
